package proxy03;

import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 动态代理实现AOP:
 *   动态指的是:在程序运行时,由JVM为我们自动生成代理类(隐式代理)
 *
 * 用到的Class类中的方法:
 *    ClassLoader getClassLoader()
 *           返回该类的类加载器。
 *
 *    Class<?>[] getInterfaces()
 *           确定此对象所表示的类或接口实现的接口。
 *
 * 我们需要通过Proxy类的方法来实现动态代理
 *   static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
 *           返回一个指定接口的代理类实例，该接口可以将方法调用指派到指定的调用处理程序。
 *
 *   第一个参数:传递一个类加载器,用来加载JVM生成的代理类,我们一般使用和被代理类(老王类)相同的加载器
 *   第二个参数:传递代理类和被代理类实现的接口(一个类实现的接口有可能多个,所以用数组接收)
 *   第三个参数:传递一个InvocationHandler接口实现类对象,InvocationHandler实现类对象绑定在代理类对象上
 *   返回值:底层会返回由JVM生成的代理类的一个实例
 *
 **/
public class Demo {
    @Test
    public void testProxy(){
        //1.传递一个类加载器
        ClassLoader cl = LaoWang.class.getClassLoader();

        //2.代理类和被代理类实现的接口
        Class<?>[] interfaces = LaoWang.class.getInterfaces();

        //3.创建InvocationHandler实现类对象
          // 因为InvocationHandler是一个接口类型，所以需要我们新创建一个类牢实现这个接口
        InvocationHandler ih = new HandlerImpl();

        // 4.调用newProxyInstance方法
        /*Object o = Proxy.newProxyInstance(cl, interfaces, ih);*/
        // 因为最后接收的不知道是什么类型，所以直接用Object类型来接收

        /* *   JVM隐式生成的代理类:
      class $Proxy1 implements OneDay{*/
        // 因为这个我们知道最后的类型是OneDay类型，我们可以直接用OneDay类型来接收
        OneDay o =(OneDay) Proxy.newProxyInstance(cl, interfaces, ih);
        // OneDay接口指向底层代理类对象，底层代理类实现了OneDay接口
        // 多态形式  编译看左边，运行看右边

        o.eat(); // invoke方法被调用
        o.play(); // invoke方法被调用
        o.sleep(); // invoke方法被调用

    }
}















